package pub.tbc.api.service.balancing;

import lombok.extern.slf4j.Slf4j;
import pub.tbc.toolkit.core.Loops;
import pub.tbc.toolkit.core.collect.Lists;

import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author tbc on 2017/3/21 17:39:29.
 */
@Slf4j
public class DefaultLoadBalancing implements LoadBalancing {
    private AtomicInteger pollIndex = new AtomicInteger(0);
    private AtomicInteger weighPollIndex = new AtomicInteger(0);

    private void listCheck(List<?> services) {
        if (services == null || services.isEmpty()) {
            throw new RuntimeException("获取服务地址出错： 服务地址列表不能为空");
        }
    }

    @Override
    public String random(List<String> services) {
        listCheck(services);
        return services.get(new Random().nextInt(services.size()));
    }

    @Override
    public synchronized String poll(List<String> services) {
        listCheck(services);
        ReentrantLock lock = new ReentrantLock();
        lock.lock();
        if (pollIndex.addAndGet(1) >= services.size()) {
            pollIndex.set(0);
        }
        lock.unlock();
        return services.get(pollIndex.get());
    }

    @Override
    public String weighRandom(List<Map<String, Integer>> services) {
        List<String> addresses = Lists.newArrayList();
        services.forEach(map -> map.forEach((k, v) -> Loops.times(v, i -> addresses.add(k))));
        return random(addresses);
    }

    @Override
    public synchronized String weighPoll(List<Map<String, Integer>> services) {
        listCheck(services);
        List<String> addresses = Lists.newArrayList();
        services.forEach(map -> map.forEach((k, v) -> Loops.times(v, i -> addresses.add(k))));
        ReentrantLock lock = new ReentrantLock();
        lock.lock();
        if (weighPollIndex.addAndGet(1) >= addresses.size()) {
            weighPollIndex.set(0);
        }
        lock.unlock();
        return addresses.get(weighPollIndex.get());
    }
}
